#include "ecb/benchmarks/ClassicalProblems.h"


#include "ecb/function/Ackley.h"
#include "ecb/function/EggHolder.h"
#include "ecb/function/Elliptic.h"
#include "ecb/function/Griewank.h"
#include "ecb/function/HyperEllipsoid.h"
#include "ecb/function/Michalewicz.h"
#include "ecb/function/Neumaier3.h"
#include "ecb/function/OddSquare.h"
#include "ecb/function/Qing.h"
#include "ecb/function/Quartic.h"
#include "ecb/function/Rana.h"
#include "ecb/function/Rastrigin.h"
#include "ecb/function/Rosenbrock.h"
#include "ecb/function/Salomon.h"
#include "ecb/function/Schaffers.h"
#include "ecb/function/Schwefel2_22.h"
#include "ecb/function/Schwefel2_26.h"
#include "ecb/function/Schwefel1_2.h"
#include "ecb/function/Sphere.h"
#include "ecb/function/Step2.h"
#include "ecb/function/Step.h"
#include "ecb/function/Whitley.h"

#include "ecb/base/Properties.h"

#include <cmath>
#include <sstream>

namespace ecb {

    ClassicalProblems::ClassicalProblems(int dim) : Benchmark("ClassicalFunctions") {

        addProblem(new Elliptic("Elliptic", "unimodal", dim, -5.12, 5.12, true));
        addProblem(new HyperEllipsoid("HyperEllipsoid", "unimodal", dim, -5.12, 5.12, true));
        addProblem(new Neumaier3("Neumaier3", "unimodal", dim, -dim*dim, dim*dim, true));
        addProblem(new Qing("Qing", "unimodal, differentiable, separable, asymmetric",
                dim, -500, 500, true));
        addProblem(new Quartic("Quartic", "unimodal", dim, -1.28, 1.28, true));
        addProblem(new Rosenbrock("Rosenbrock", "unimodal for n < 4", dim, -2.048, 2.048, true));
        addProblem(new Schwefel1_2("Schwefel1_2", "unimodal a.k.a. Quadric", dim, -100, 100, true));
        addProblem(new Schwefel2_22("Schwefel2_22", "unimodal, non-differentiable, separable, symmetric",
                dim, -100, 100, true));
        addProblem(new Sphere("Sphere", "unimodal", dim, -5.12, 5.12, true));
        addProblem(new Step2("Step2", "unimodal, discontinuous, non-differentiable, separable, symmetric",
                dim, -500, 500, true));
        addProblem(new Step("Step", "unimodal", dim, -5.12, 5.12, true));

        addProblem(new Ackley("Ackley", "multimodal", dim, -32.768, 32.768, true));
        addProblem(new EggHolder("EggHolder", "multimodal", dim, -512, 512, true));
        addProblem(new Griewank("Griewank", "multimodal, differentiable, non-separable, symmetric",
                dim, -600, 600, true));
        addProblem(new Michalewicz("Michalewicz", "multimodal", dim, 0, M_PI, true));
        addProblem(new OddSquare("OddSquare", "multimodal", dim, -5 * M_PI, 5 * M_PI, true));
        addProblem(new Rana("Rana", "multimodal", dim, -512, 512, true));
        addProblem(new Rastrigin("Rastrigin", "multimodal", dim, -5.12, 5.12, true));
        addProblem(new Salomon("Salomon", "multimodal, differentiable, non-separable, symmetric",
                dim, -100, 100, true));
        addProblem(new Schaffers("Schaffers", "multimodal", dim, -100, 100, true));
        addProblem(new Schwefel2_26("Schwefel2_26", "multimodal, non-differentiable, separable, symmetric",
                dim, -500, 500, true));

        addProblem(new Whitley("Whitley", "multimodal, differentiable, non-separable, symmetric",
                dim, -100, 100, true));



        for (int i = 0; i < numberOfProblems(); ++i) {
            Problem* p = getProblem(i);

            std::stringstream f_name;
            f_name << "F";
            if (i + 1 < 10) f_name << "0";
            f_name << (i + 1);
            p->properties()->setName(f_name.str());
        }

        //WARNING: Qing and Quartic are similar
        //WARNING: Sphere and Step2 are similar
        //WARNING: Whitley and Schaffers are weird

    }



}
